package ch.myDungeons.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import ch.myDungeons.game.GameData;
import ch.myDungeons.game.Map;
import ch.myDungeons.game.MyDungeon;

/**
 * IO Stream, used to save and load game Data as savegames, maps and items
 * @author Grii
 *
 */

public class IOStream {
	
	static String dataDir = "ch/myDungeons/data";
	static String saveDir = "MyDungeons/savegames";
	static String languageDir = dataDir + "/language_packs";
	
	public static String helpFile = "";
	
	static{
		loadHelpFile();
	}
	
	/** Loads a game */
	public static GameData load(String name){
		GameData gameData = null;
	    try {
	    	FileInputStream fileIn = new FileInputStream(saveDir + "/" + name + ".savegame");
	    	ObjectInputStream in = new ObjectInputStream(fileIn);
	    	gameData = (GameData) in.readObject();
	    	in.close();
			fileIn.close();
			for (int i = 0; i < gameData.getMaps().length; i++) {
				for (int j = 0; j < gameData.getMaps()[i].tiles.length; j++) {
					for (int j2 = 0; j2 < gameData.getMaps()[i].tiles[0].length; j2++) {
						if (gameData.getMaps()[i].tiles[j][j2].personOnTheTile != null) {
							gameData.getMaps()[i].tiles[j][j2].personOnTheTile.setConsole(MyDungeon.game.gameFrame.getConsole());
						}
					}
				}
			}
		} catch(IOException i) {
			i.printStackTrace();
		} catch(ClassNotFoundException c) {
			System.out.println("Employee class not found");
			c.printStackTrace();
		}
	    return gameData;
	}
	
	/** Saves a game */
	public static boolean save(GameData gameData) {
		checkDir(saveDir);
		try {
	         FileOutputStream fileOut = new FileOutputStream(saveDir + "/" + gameData.getName()+".savegame");
	         ObjectOutputStream out = new ObjectOutputStream(fileOut);
	         out.writeObject(gameData);
	         out.close();
	         fileOut.close();
	         return true;
	      } catch(IOException i) {
	          i.printStackTrace();
	          return false;
	      }
	}
	
	/** Loads a game from a String
	 * @deprecated */
	@Deprecated
	public static GameData loadFromString(String name){
		String loadedFile = loadFile(saveDir, name+".savegame");
		loadedFile = loadedFile.replaceAll("\n", "");
	    String[] mapStrings = loadedFile.split("<MAP>");
	    String[] gameInfoStrings = mapStrings[0].split("<GAMEINFO>");
	    String playerName = gameInfoStrings[0];
	    int mapLevel = Integer.parseInt(gameInfoStrings[1]);
	    int turnNumber = Integer.parseInt(gameInfoStrings[2]);
	    int mapCount = Integer.parseInt(gameInfoStrings[3]);
	    Map[] maps = new Map[mapCount];
	    
	    for (int i = 0; i < mapCount; i++) {
	    	 maps[i] = MapGenerator.createMapFromSavedString(mapStrings[i+1]);
		}
	    
	    GameData loadedGame = new GameData(playerName, maps, mapLevel, turnNumber);
	    return loadedGame;
	}
	
	/** Saves a game to a String
	 * @deprecated */
	@Deprecated
	public static boolean saveAsString(GameData gameData) {
		checkDir(saveDir);
		try {
			boolean success = true;
			int stringLength = 0;
			FileWriter fstream = new FileWriter(saveDir + "/" + gameData.getName()+".savegame");
			BufferedWriter out = new BufferedWriter(fstream);
			
			String headerString = gameData.getName() + "<GAMEINFO>" + gameData.getMapLevel() + "<GAMEINFO>" + gameData.getTurnNumber() + "<GAMEINFO>" + gameData.getMaps().length;
			stringLength += headerString.length();
			out.write(headerString);
			out.newLine();
			
			for (int i = 0; i < gameData.getMaps().length; i++) {
				out.write("<MAP>");
				String tmpMapString = gameData.getMaps()[i].getSave();
				out.write(tmpMapString);
				out.newLine();
				stringLength += 6 + tmpMapString.length();
			}
			
			out.close();
			
			System.out.println(stringLength+"/2147483647 used. " + (2147483647-stringLength) + " left");
			System.out.println((2147483647/stringLength) + "x that would be possible");
			if (stringLength >= 2147483647) {
				success = false;
			}
			if (success) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			System.err.println("Error: " + e.getMessage());
			return false;
		}
	}
	
	/** Returns the content of the help file */
	public static String loadHelpFile(){
		String help = loadInternalFile(dataDir, "help.txt");
		helpFile = help;
		return help;
	}
	
	
	/** Loads a file */
	public static String loadInternalFile(String completeDir, String fileName){
		//checkDir(completeDir + "/" + fileName);
		StringBuilder contents = new StringBuilder();
		InputStream is = Class.class.getResourceAsStream("/" + completeDir + "/" + fileName);        
		InputStreamReader isr = new InputStreamReader(is);
	    try {
	      BufferedReader input =  new BufferedReader(isr);
	      try {
	        String line = null;
	        while ((line = input.readLine()) != null){
	        	if (!line.startsWith("//")) {
	        		contents.append(line + "\n");
				}
	        	
	        }
	      }
	      finally {
	        input.close();
	      }
	    }
	    catch (Exception ex){
	      ex.printStackTrace();
	    }
	    
	    String loadedFile = contents.toString();
		return loadedFile;
	}
	
	/** Loads a file */
	public static String loadFile(String completeDir, String fileName){
		checkDir(completeDir + "/" + fileName);
		StringBuilder contents = new StringBuilder();
	    try {
	      BufferedReader input =  new BufferedReader(new FileReader(completeDir + "/" + fileName));
	      try {
	        String line = null;
	        while ((line = input.readLine()) != null){
	        	if (!line.startsWith("//")) {
	        		contents.append(line + "\n");
				}
	        	
	        }
	      }
	      finally {
	        input.close();
	      }
	    }
	    catch (Exception ex){
	      ex.printStackTrace();
	    }
	    
	    String loadedFile = contents.toString();
		return loadedFile;
	}
	
	/** Checks if a character exists */
	public static boolean checkCharacterName(String name){
		File file = new File(saveDir + "/" + name + ".savegame");
		if (!file.exists()) {
			return false;
		}
		return true;
	}
	
	/** Check the directory where the files are located */
	public static void checkDir(String directory) {
		File file = new File(directory);
		if (!file.exists()) {
			if (file.mkdir()) {
				System.out.println("Directory is created!");
			} else {
				System.out.println("Failed to create directory!");
			}
		}
	}

	/** Loads a language file */
	public static String loadLanguageFile(String language) {
		String lang = loadInternalFile(languageDir, language + ".lang");
		lang = lang.replaceAll("\\n+", "\n");
		return lang;
	}

	public static String[] loadPersonDataFile() {
		String string = loadInternalFile(dataDir, "enemyTypes.dat");
		string = string.replaceAll("\\n+", "\n");
		string = string.replaceAll("  ", " ");
		if (string.endsWith("\n")) {
			string = string.substring(0, string.length()-1);
		}
		String[] monsters = string.split("\n");
		return monsters;
	}
	
	public static String[] loadWeaponDataFile() {
		String string = loadInternalFile(dataDir, "weaponTypes.dat");
		string = string.replaceAll("\\n+", "\n");
		string = string.replaceAll("  ", " ");
		if (string.endsWith("\n")) {
			string = string.substring(0, string.length()-1);
		}
		String[] monsters = string.split("\n");
		return monsters;
	}
	
	public static String[] loadArmorDataFile() {
		String string = loadInternalFile(dataDir, "armorTypes.dat");
		string = string.replaceAll("\\n+", "\n");
		string = string.replaceAll("  ", " ");
		if (string.endsWith("\n")) {
			string = string.substring(0, string.length()-1);
		}
		String[] monsters = string.split("\n");
		return monsters;
	}
}
